#!/bin/bash

# Provide source directive to shellcheck.
# shellcheck source=meta-facebook/meta-yosemite4/recipes-phosphor/state/phosphor-state-manager/power-cmd
source /usr/libexec/phosphor-state-manager/power-cmd
# shellcheck source=meta-facebook/meta-yosemite4/recipes-yosemite4/plat-tool/files/yosemite4-common-functions
source /usr/libexec/yosemite4-common-functions

GPIOCHIP_IO_EXP_SLOT_PWR_CTRL=$(basename "/sys/bus/i2c/devices/$SPIDER_BOARD_IO_EXP_BUS_NUM-00$IO_EXP_SLOT_PWR_CTRL_ADDR/"*gpiochip*)

log_message() {
    local slot_num=$(($1+1))
    local MESSAGE="SLOT$slot_num $2 Power Fault"
    local COMBINED_INFO="$3"

    busctl call \
        xyz.openbmc_project.Logging /xyz/openbmc_project/logging \
        xyz.openbmc_project.Logging.Create Create "ssa{ss}" "$MESSAGE" \
        "xyz.openbmc_project.Logging.Entry.Level.Error" 1 "FAULT" "$COMBINED_INFO"
}

host_power_status() {
    id=$1
    service_path="xyz.openbmc_project.State.Host${id}"
    object_path="/xyz/openbmc_project/state/host${id}"
    interface_path="xyz.openbmc_project.State.Host"
    property="CurrentHostState"
    status=$(busctl get-property "$service_path" "$object_path" $interface_path $property | cut -d"." -f6)
    if [ "$status" == "Running\"" ]; then
        echo "on"
    else
        echo "off"
    fi
}

check_power_control_is_executed() {
    id=$1
    check_service=("chassis-powercycle@$id.service" "chassis-poweron@$id.service" "chassis-poweroff@$id.service" "host-powercycle@$id.service" "host-poweron@$id.service" "host-poweroff@$id.service")

    for service in "${check_service[@]}"; do
        status=$(systemctl is-active "$service")
        if [ "$status" == "activating" ]; then
            echo "true"
            exit 0
        fi
    done
    echo "false"
    exit 0
}

# Sleep for 10ms to ignore GPIO instability during blade hot-plug
usleep 10000

if [ "$1" = "slot1-slot4" ]; then
    i2c_bus=8
    mux_addr=0x70
    slot_num_offset=0
elif [ "$1" = "slot5-slot8" ]; then
    i2c_bus=9
    mux_addr=0x71
    slot_num_offset=4
else
    echo "Invalid input: $1"
    exit 1
fi

count=0
check_count=0
SLOT_RANGE=4
CLEAR_BIT=20
while [ $check_count -lt $SLOT_RANGE ]
do
    count=0

    # i2ctranster to check which slot got interrupt
    read -r INT_BYTE <<< "$(i2ctransfer -f -y $i2c_bus w1@$mux_addr 0 r1)"
    INT_BYTE=$((INT_BYTE >> 4))

    if [ $INT_BYTE -eq 0 ]; then
        exit 0
    fi

    while [ $count -lt $SLOT_RANGE ]
    do
        slot_num=$((count + slot_num_offset))
        host_id=$((slot_num + 1))

        # Skip checking if chassis is power-off
        chassis_status=$(gpio_get "$GPIOCHIP_IO_EXP_SLOT_PWR_CTRL" "$slot_num")
        if [ "$chassis_status" == "$STATE_OFF" ]
        then
            count=$((count + 1))
            echo "Chassis$host_id is power-off, skipped"
            continue
        fi

        fault=$(( (INT_BYTE >> count) & 1 ))
        # if fault[i] == 1, means slot_x got ISR
        if [ $fault -eq 1 ]; then
            # i2ctranster to get CPLD IOE (0x24) addr 0x01 (port1, ac)
            read -r FAULT_BYTE <<< "$(i2ctransfer -f -y $slot_num w1@0x24 0x01 r1)"

            # check which pin fault, add to fault info
            if (( (FAULT_BYTE >> 0) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_P1V8_STBY_FAULT" || COMBINED_INFO="PWRGD_P1V8_STBY_FAULT"
            elif (( (FAULT_BYTE >> 1) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_P1V2_STBY_FAULT" || COMBINED_INFO="PWRGD_P1V2_STBY_FAULT"
            fi

            # call logging function
            if [ -n "$COMBINED_INFO" ]; then
                log_message $slot_num "AC" "$COMBINED_INFO"
            fi

            # clean
            COMBINED_INFO=""
            # i2ctranster to get CPLD IOE (0x24) addr 0x02 (port2, dc)
            read -r FAULT_BYTE <<< "$(i2ctransfer -f -y $slot_num w1@0x24 0x02 r1)"

            # check which pin fault, add to fault info
            if (( (FAULT_BYTE >> 0) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_PVDDCR_CPU1_FAULT" || COMBINED_INFO="PWRGD_PVDDCR_CPU1_FAULT"
            elif (( (FAULT_BYTE >> 1) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_PVDDCR_CPU0_FAULT" || COMBINED_INFO="PWRGD_PVDDCR_CPU0_FAULT"
            elif (( (FAULT_BYTE >> 2) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_PVDDCR_SOC_FAULT" || COMBINED_INFO="PWRGD_PVDDCR_SOC_FAULT"
            elif (( (FAULT_BYTE >> 3) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_PVDDIO_FAULT" || COMBINED_INFO="PWRGD_PVDDIO_FAULT"
            elif (( (FAULT_BYTE >> 4) & 1 == 1 )); then
                [ -n "$COMBINED_INFO" ] && COMBINED_INFO="${COMBINED_INFO},PWRGD_PVDD11_S3_R_FAULT" || COMBINED_INFO="PWRGD_PVDD11_S3_R_FAULT"
            fi

            # call logging function
            if [ -n "$COMBINED_INFO" ]; then
                log_message $slot_num "DC" $COMBINED_INFO
            fi


            # Confirm whether power-control is being executed to avoid repeated execution
            result=$(check_power_control_is_executed $host_id)
            if [ "$result" == "false" ]; then
                echo "Power state changes not caused by power-control on Host$host_id"

                # Check CPU power status
                read -r PWR_STATUS_BYTE <<< "$(i2ctransfer -f -y $slot_num w1@0x23 0x02 r1)"
                if (( (PWR_STATUS_BYTE >> 2) & 1 == 1 )); then
                    if [ "$(host_power_status $host_id)" == "off" ]; then
                        echo "Currently, the CPU is powered on, but the host state is off in D-Bus"
                    fi
                else
                    if [ "$(host_power_status $host_id)" == "on" ]; then
                        echo "Host$host_id power status change to off"
                        busctl set-property xyz.openbmc_project.State.Host$host_id /xyz/openbmc_project/state/host$host_id xyz.openbmc_project.State.Host RequestedHostTransition s "xyz.openbmc_project.State.Host.Transition.Off"
                    fi
                fi
            else
                echo "Power state changes caused by power-control on Host$host_id, just clear interrupt"
            fi

            # Clear interrupt
            cpld_ioe_chip=$(basename "/sys/bus/i2c/devices/$slot_num-0021/"*gpiochip*)

            if ! gpio_set "$cpld_ioe_chip" "$CLEAR_BIT"=1
            then
                echo "Set slot_num: $slot_num register to clear interrupt fail"
            fi

            usleep 5000

            if ! gpio_set "$cpld_ioe_chip" "$CLEAR_BIT"=0
            then
                echo "Set slot_num: $slot_num register to default status fail"
            fi
        fi

        count=$((count + 1))
    done

    check_count=$((check_count + 1))
done
